#include "bsp_i2c.h"
#include "bsp_gpio.h"
#include "bsp_delay.h"
#include "stdio.h"


/* 初始化I2C */
void i2c_init(I2C_Type *base)
{

	base->I2CR &= ~(1 << 7);		/* 关闭I2C */
	/* 设置I2C时钟 */
	base->IFDR = 0x15 << 0;			/* 640分频，IPG_CLK=66MHZ/640=103.125KHz */
	base->I2CR |= (1 << 7);			/* 使能I2C */
}




/* I2C Start 信号产生以及从机地址 */
unsigned char i2c_master_start(I2C_Type *base, unsigned char address, 
								enum i2c_direction direction)
{
	uint8_t ack;

	/* 判断是否为忙 */
	if((base->I2SR & (1 << 5)))
	{
		/* 当前I2C忙 */
		return 1;
	}

	/* 设置为主机模式 */
	// base->I2CR |= (1 << 5);			/* bit[5]主机模式 Master */
	// base->I2CR |= (1 << 4);			/* bit[4]主机发送模式 Tx*/
	base->I2CR |= (1 << 5) | (1 << 4);


	//清除IIF中断标志
	I2C1->I2SR &= ~(1 << 1);

	/* 产生Start 信号 */
	/* I2C从设备地址(bit[7:1]) */
	/* bit[0] 0 表示写，1表示read */
	base->I2DR = ((unsigned int)address) << 1 | ((direction == kI2C_Write)? 0 : 1);

	return 0;
}


/* I2C Stop信号 */
unsigned char i2c_master_stop(I2C_Type *base)
{
	unsigned short timeout = 0xFFFF;

	/* bit[3] Transmit acknowledge enable， */
	/* bit[4] Transmit/Receive mode select， */
	/* bit[5] master/slave mode select, 软件清0产生一个stop信号 */
	//base->I2CR &= ~(1 << _I2C_I2CR_TXAK_SHIFT) | ~(1 << _I2C_I2CR_MTX_SHIFT) | ~(1 << _I2C_I2CR_MSTA_SHIFT);
	base->I2CR &= ~((1 << 3) | (1 << 4) | (1 << 5));

	/* 检查busy */
	while(base->I2SR & (1 << _I2C_I2SR_IBB_SHIFT)){
		timeout--;
		if(timeout == 0){
			return I2C_STATUS_TIMEOUT;
		}
	}

	return I2C_STATUS_OK;
}

/* repeat-restart 信号*/
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address, 
								enum i2c_direction direction)
{
	/* 判断是否为忙并且工作在从机模式下*/
	//if((base->I2SR & (1 << 5)) && ((base->I2CR &= (1 << 5)) == 0))
	if((base->I2SR & (1 << 5)) && ((base->I2CR & (1 << 5)) == 0))
	{
		/* 判断是否为忙并且工作在从机模式下*/
		return 1;
	}

	/* bit[2] 写1生成一个repeat-start信号 */
	/* bit[5] 写1 master模式 */
	/* bit[4] 写1 tx模式 */
	base->I2CR |=  (1 << 4) | (1 << 2);

	/* 写从机地址 */
	base->I2DR = ((unsigned int)address) << 1 | 
				((direction == kI2C_Write)? 0 : 1);

	return 0;
}

/* 错误检查和清除函数 */
unsigned char  i2c_check_and_clear_error(I2C_Type *base, unsigned int state)
{
	/* 先检查是否为仲裁丢失错误 */

	/* 仲裁丢失 */
	if(state & (1 << 4)){
		base->I2SR &= ~(1 << 4); 	/* 先清除标志位 */
		base->I2CR  &= ~(1 << 7);		/* 关闭I2C*/
		base->I2CR  |= (1 << 7);		/* 重新打开I2C, 关闭打开复位I2C */
		return I2C_STATUS_ARBITRATIONLOST;
	}

	/* 收到NACK信号 */
	else if(state & (1 << 0)){
		return I2C_STATUS_NAK;
	}
	
	return I2C_STATUS_OK;
}


/* 发送数据函数 */
void i2c_master_write(I2C_Type *base, const unsigned char *buf, unsigned int size)
{
	//等待上一个发送传输完成
	while(!(base->I2SR & (1 << 7)));

	//清除中断标记位
	base->I2SR &= ~(1 << 1);

	/* 发送模式 */
	base->I2CR |= (1 << 4);

	while(size--)
	{
		base->I2DR = *buf++;

		/* 参考NXP的SDK驱动, bit[1]中断标志位，等待数据发送完成 */
		//while(!(base->I2SR << (1 << 1)));
		while(!(base->I2SR & (1 << 1)));
		base->I2SR &= ~(1 << 1);

		/* 每发送8bit 检查ACK */
		//if(i2c_check_and_clear_error(base, base->I2SR) != I2C_STATUS_OK){
		if(i2c_check_and_clear_error(base, base->I2SR)){
			/* 有错误发生 */
			break;
		}
	}

	/* bit[1]中断标志位  */
	//base->I2SR = ~(1 << 1);
	base->I2SR &= ~(1 << 1);

	/* Stop 停止位 */
	i2c_master_stop(base);
}

/* 读数据函数 */
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size)
{
	volatile uint8_t dummy = 0;		/* 假读 */

	/* clean compile warning */
	dummy++;

	//等待上一个发送传输完成
	while((base->I2SR & (1 << 7)) == 0);

	/* bit[1]中断标志位  */
	base->I2SR = ~(1 << 1);

	base->I2CR &= ~( 1<< 4);	/* bit[4] MTX Select, 选择Rx */
	base->I2CR &= ~(1 << 3);	/* bit[3] TXAK 发送ACK */

	if(size == 1){
		/* 参考NXP的SDK驱动, 发送NACK信号 */
		base->I2CR |= (1 << 3);
	}

	/* dummy read */
	dummy = base->I2DR;

	while(size--)
	{
		/* 等待数据接收完成 */
		while(!(base->I2SR & (1 << 1)));		/* 等待数据传输完成 */
		/* bit[1]中断标志位  */
		base->I2SR = ~(1 << 1);

		if(size == 1){
			/* 参考NXP的SDK驱动, 发送NACK信号 */
			base->I2CR |= (1 << 3);
		}

		if(size == 0){
			/* 数据发送完成 */
			i2c_master_stop(base);
		}

		/* 读取当前已接收数据，并触发下一次接收 */
		*buf++ = base->I2DR;
	}
}


/*
 * @description	: I2C数据传输，包括读和写
 * @param - base: 要使用的IIC
 * @param - xfer: 传输结构体
 * @return 		: 传输结果,0 成功，其他值 失败;
 */
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer)
{
	unsigned char ret = 0;
	enum i2c_direction direction = xfer->direction;	

	base->I2SR &= ~((1 << 1) | (1 << 4));			/* 清除标志位，中断标志位和仲裁丢失标志位 */

	/* 等待传输完成 */
	while(!((base->I2SR >> 7) & 0X1)){}; 

	/* 如果是读的话，要先发送寄存器地址，所以要先将方向改为写 */
    if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read))
    {
        direction = kI2C_Write;
    }

	ret = i2c_master_start(base, xfer->slaveAddress, direction); /* 发送开始信号 */
    if(ret)
    {	
		return ret;
	}

	while(!(base->I2SR & (1 << 1))){};			/* 等待传输完成 */

    ret = i2c_check_and_clear_error(base, base->I2SR);	/* 检查是否出现传输错误 */
    if(ret)
    {
      	i2c_master_stop(base); 						/* 发送出错，发送停止信号 */
        return ret;
    }
	
    /* 发送寄存器地址 */
    if(xfer->subaddressSize)
    {
        do
        {
			base->I2SR &= ~(1 << 1);			/* 清除标志位 */
            xfer->subaddressSize--;				/* 地址长度减一 */
			
            base->I2DR =  ((xfer->subaddress) >> (8 * xfer->subaddressSize)); //向I2DR寄存器写入子地址
  
			while(!(base->I2SR & (1 << 1)));  	/* 等待传输完成 */

            /* 检查是否有错误发生 */
            ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	i2c_master_stop(base); 				/* 发送停止信号 */
             	return ret;
            }  
        } while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));

        if(xfer->direction == kI2C_Read) 		/* 读取数据 */
        {
            base->I2SR &= ~(1 << 1);			/* 清除中断挂起位 */
            i2c_master_repeated_start(base, xfer->slaveAddress, kI2C_Read); /* 发送重复开始信号和从机地址 */
    		while(!(base->I2SR & (1 << 1))){};/* 等待传输完成 */

            /* 检查是否有错误发生 */
			ret = i2c_check_and_clear_error(base, base->I2SR);
            if(ret)
            {
             	ret = I2C_STATUS_ADDRNAK;
                i2c_master_stop(base); 		/* 发送停止信号 */
                return ret;  
            }
           	          
        }
    }	


    /* 发送数据 */
    if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0))
    {
    	i2c_master_write(base, xfer->data, xfer->dataSize);
	}

    /* 读取数据 */
    if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0))
    {
       	i2c_master_read(base, xfer->data, xfer->dataSize);
	}
	return 0;	
}




